package com.esunrising.esungsc.common.generator;


import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 用于生成实体、Controller、Service、代码的类
 */
@Service
public final class CodeGenerator {

    private final JdbcTemplate jdbcTemplate;

    public CodeGenerator(JdbcTemplate jdbcTemplate){
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * 下划线转驼峰
     */
    private String underlineToCamel(String str){
        StringBuilder result = new StringBuilder();
        String[] a = str.split("_");
        for (String s : a) {
            if(result.length() == 0){
                result.append(s.toLowerCase());
            }else {
                result.append(s.substring(0,1).toUpperCase()); //首字母大写
                result.append(s.substring(1).toLowerCase());//非首字母小写
            }
        }
        return result.toString();
    }

    /**
     * 生成Java Class文件
     * @param path
     * @param templateName
     * @param className
     * @param params
     */
    private void generateClass(String path, String templateName, String className, Map<String, Object> params){
        Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);
        configuration.setDefaultEncoding("UTF-8");
        configuration.setClassLoaderForTemplateLoading(Configuration.class.getClassLoader(), "templates");
        try{
            Template template = configuration.getTemplate(templateName);
            template.process(params, Files.newBufferedWriter(Path.of(path+className+".java")));
        }catch (IOException| TemplateException e){
            throw new RuntimeException(e);
        }
    }
    /**
     * 生成实体类
     */
    public void generateEntity(String entityPath, String basePackage, String tableName, String className, String tableComment){
        String sql = "select c.column_name, c.data_type column_type, nvl(cm.comments,'-') column_comment  " +
                " from user_tab_cols c left join user_col_comments cm " +
                " on c.table_name = cm.table_name and c.column_name = cm.column_name " +
                " where c.table_name = '" + tableName + "' " +
                " order by c.column_id";
        List<EsunField> fields = jdbcTemplate.queryForList(sql)
                .stream()
                .map(this::buildFieldFromMap)
                .filter(field->!Set.of("esunApiDwbh", "esunApiOrgid", "esunApiOrgcode", "esunApiLedger", "esunApiUpdate").contains(field.getName()))
                .collect(Collectors.toList());

        // 构造freeMaker参数
        Map<String, Object> params = Map.of("fields", fields, "className", className, "tableName", tableName, "basePackage", basePackage, "tableComment", tableComment);
        // 生成Java Class文件
        generateClass(entityPath, "entity.java.ftl", className, params);
    }

    /**
     * 将特定结构的map转化为自定义子段类型
     * @param map
     * @return
     */
    private EsunField buildFieldFromMap(Map<String, Object> map){
        String columnName = map.get("column_name").toString();
        String columnType = map.get("column_type").toString();
        String columnComment = map.get("column_comment").toString();

        // 获取字段类型枚举
        EsunFieldType fieldType = EsunFieldType.of(columnType).orElse(EsunFieldType.VARCHAR);
        String name = underlineToCamel(columnName);

        return new EsunField(name, columnName, fieldType, columnComment);
    }

    /**
     * 生成控制器类
     */
    public void generateController(String controllerPath, String basePackage, String className, String tableComment){
        // 构造freeMaker参数
        Map<String, Object> params = Map.of("className", className,"basePackage", basePackage, "tableComment", tableComment);
        // 生成Java Class文件
        generateClass(controllerPath, "controller.java.ftl", className+"Controller", params);
    }


    private void generateDao(String daoPath, String basePackage, String className) {
        // 构造freeMaker参数
        Map<String, Object> params = Map.of(
                "className", className,
                "basePackage", basePackage);

        // 生成Java Class文件
        generateClass(daoPath, "dao.java.ftl", className + "Dao", params);
    }
    private void generateServiceImpl(String serviceImplPath, String basePackage, String className) {
        // 构造freeMaker参数
        Map<String, Object> params = Map.of(
                "className", className,
                "basePackage", basePackage);

        // 生成Java Class文件
        generateClass(serviceImplPath, "serviceImpl.java.ftl", className + "ServiceImpl", params);
    }

    private void generateService(String servicePath, String basePackage, String className) {
        // 构造freeMaker参数
        Map<String, Object> params = Map.of(
                "className", className,
                "basePackage", basePackage);

        // 生成Java Class文件
        generateClass(servicePath, "service.java.ftl", className + "Service", params);
    }

    /**
     * 将path转换为包名
     */
    private String pathToPackage(String path) {
        return path.replace("/", ".").replace("\\", ".");
    }

    /**
     * 按数据库表名生成Java常用代码
     * @param basePath 基本文件路径，如 com/esunrising/esungsc
     * @param tableName 数据库表名，如 T_API_HSDW
     * @param className Java Class基本名称，如 ApiHsdw
     */
    public void generate(String basePath, String tableName, String className, String tableComment ) {
        String entityPath = "src/main/java/" + basePath + "/entity/";
        String basePackage = pathToPackage(basePath);
        generateEntity(entityPath, basePackage, tableName, className, tableComment);


        String daoPath = "src/main/java/" + basePath + "/dao/";
        generateDao(daoPath, basePackage, className);

        String servicePath = "src/main/java/" + basePath + "/service/";
        generateService(servicePath, basePackage, className);

        String serviceImplPath = "src/main/java/" + basePath + "/service/impl/";
        generateServiceImpl(serviceImplPath, basePackage, className);

        String controllerPath = "src/main/java/" + basePath + "/controller/";
        generateController(controllerPath, basePackage, className, tableComment);

        /*

        */
    }
}
